#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <string>
#include <cerrno>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include"ThreadPool.hpp"
#include"Task.hpp"
// void ServerIO(int new_sock)
// {
//     char recvBuf[1024];
//     while (1)
//     {
//         memset(recvBuf, 0, sizeof(recvBuf));
//         std::cout << "waitting client send to me message......" << std::endl;
//         ssize_t sz = read(new_sock, recvBuf, sizeof(recvBuf) - 1);
//         if (sz > 0)
//         {
//             recvBuf[sz] = 0;
//             std::cout << "client to :" << recvBuf << std::endl;
//             std::string echo_str = recvBuf;
//             echo_str += "  <-----我是服务器发送的";
//             write(new_sock, echo_str.c_str(), echo_str.size());
//         }
//         else if (sz == 0)
//         {
//             std::cout << "client close!" << std::endl;

//             break;
//         }
//         else
//             break;
//     }
// }
// void *HandlerRequest(void *argc)
// {
//     pthread_detach(pthread_self()); //分离为的是：线程退出回收自己的资源即可，不用主线程等待
//     int new_sock = *(int *)argc;
//     delete (int *)argc;
    
//     ServerIO(new_sock);
//     close(new_sock);
//     return (void *)0;
// }
// ./tcp_server port
int main(int argc, char **argv)
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " port" << std::endl;
        return 1;
    }

    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        std::cerr << "socket error: " << errno << std::endl;
        return 2;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[1]));
    server_addr.sin_addr.s_addr = INADDR_ANY;

    socklen_t server_addr_len = sizeof(server_addr);

    if (bind(listen_sock, (struct sockaddr *)&server_addr, server_addr_len) < 0)
    {
        std::cerr << "bind() failed:" << errno << std::endl;
        return 3;
    }

    if (listen(listen_sock, 5) < 0)
    {
        std::cerr << "listen error" << std::endl;
        return 4;
    }

    // signal(SIGCHLD,SIG_IGN); //父进程忽略子进程退出的信号，子进程会自动退出释放资源
    for (;;)
    {
        struct sockaddr_in peer_addr;
        memset(&peer_addr, 0, sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);

        int new_sock = accept(listen_sock, (struct sockaddr *)&peer_addr, &peer_addr_len);
        if (new_sock < 0)
        {
            continue;
        }
        std::cout << "get new client ip:" << inet_ntoa(peer_addr.sin_addr) << " port = " << ntohs(peer_addr.sin_port) << std::endl;
       
       //***************************************************************//
       //version 4:线程池版本
       //当accept成功后，就表明来了一个任务，服务器要处理

       //1.构建一个存储accept到来的任务对象
       Task t(new_sock);
       //2.把任务放到后端的线程池中，让线程池中的线程去处理任务
       ThreadPool<Task>::GetInstance()->InitThreadPool(); //构建线程池
       ThreadPool<Task>::GetInstance()->PushTask(t); //把任务放入到线程池处理

       //***************************************************************//
        // version 3
        //多线程处理
        //主线程的listen_sock是会被子线程共享的，子线程不可能关主线程的listen_sock，关了就会出大事

        /*
        这个多线程版本有两个问题：
                a.创建线程无上限问题，服务器容易被攻击瘫痪
                b.只有客户端到来了，服务端才开始创建线程，当大量客户端来时候，此时船舰线程就花费成本了
        //解决办法：线程池！
        */

        // pthread_t tid;
        // int *parm = new int(new_sock);
        // if (pthread_create(&tid, nullptr, HandlerRequest, (void *)parm) < 0)
        // {
        //     std::cerr << "Error creating thread" << errno << std::endl;
        //     return 5;
        // }

        //***************************************************************//
        // version 2
        // //多进程
        // pid_t pid = fork();
        // if (pid < 0)
        // {
        //     continue;
        // }
        // else if (pid == 0)
        // {
        //     close(listen_sock); //子进程会继承父进程的fd,由于子进程不使用父进程的fd，所以就关
        //     ServerIO(new_sock);
        //     close(new_sock); //子进程退出之前，关闭自己的文件描述符，如果不关闭，会导致fd泄漏问题
        //     exit(0); //子进程退出，父进程需要如何处理呢？处理方式waitpid ，这个又分阻塞等待和非阻塞等待
        //             //假如父进程是阻塞等待，那多进程也和单进程没区别，父进程依旧需要等等子进程退出，才可以处理自己的任务
        //             //假如是非阻塞等待呢？也不好，原因是假如非阻塞的话，父进程要不断等处理任务IO的释放问题！
        //             //最好的方式是忽略子进程退出信号
        // }
        // else
        // {
        //     //父进程
        //     close(new_sock); //父进程关闭子要给子进程通信的new_sock,因为子进程已经继承到了new_sock，而父进程不需要了
        //     //不干事，while会回到最开始的代码，然父进程不断的accept
        // }
        //***************************************************************//
        // version 1
        // ServerIO(new_sock);
    }
    return 0;
}
